﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Diagnostics;

namespace Auction_Boxing_2
{


    public class BoxingPlayer : IComparable<BoxingPlayer>
    {
        #region stats
        protected float maxhealth;

        public float MaxHealth
        {
            get
            {
                return maxhealth;
            }
            set
            {
                maxhealth = value;
            }
        }

        protected float maxstamina;

        public float MaxStamina
        {
            get
            {
                return maxstamina;
            }
            set
            {
                maxstamina = value;
            }
        }

        protected float maxmovement;

        public float MaxMovement
        {
            get
            {
                return maxmovement;
            }
            set
            {
                maxmovement = value;
            }
        }

        protected float maxcooldown;

        public float MaxCoolDown
        {
            get { return maxcooldown; }
            set { maxcooldown = value; }
        }

        protected float currenthealth;

        public float CurrentHealth
        {
            get { return currenthealth; }
            set { currenthealth = value; }
        }

        protected float currentstamina;

        public float CurrentStamina
        {
            get { return currentstamina; }
            set { currentstamina = value; }
        }

        public float CurrentCooldown
        {
            get { return CurrentCooldown; }
            set { CurrentCooldown = value; }
        }

        #endregion

        #region some stuff

        int width;
        public int Width
        {
            get { return width; }
            set { width = value; }
        }

        int height;
        public int Height
        {
            get { return height; }
            set { height = value; }
        }

        public int playerindex;
        public bool isActive;
        public bool isAttacking;
        public bool isHit;

        const int TimerInterval = 190;
        const int WaitTimerInterval = 8;

        // For Bleeding Money effect
        public List<Texture2D> hit_textures = new List<Texture2D>();
        public List<ParticleEngine> particleEngines_hit = new List<ParticleEngine>();

        //Shadow fields.
        Texture2D tShadow;
        public Rectangle rShadow;



        #endregion

        #region important stuff
        // List of keys currently down
        List<KeyPressed> keysPressed = new List<KeyPressed>();

        public List<KeyPressed> KeysDown
        {
            get
            {
                return keysPressed;
            }


        }

        string sname;

        //Inputs
        public Input_Handler input;

        //Position Vector
        public Vector3 position;

        public Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;

            }
        }

        //speed vector
        Vector3 speed;

        public Vector3 Speed
        {
            get
            {
                return speed;
            }
            set
            {
                speed = value;
            }
        }

        //hurtbox
        public Rectangle hurtbox;

        public Rectangle Hurtbox
        {
            get
            {
                return hurtbox;
            }
            set
            {
                hurtbox = value;
            }
        }




        AnimationPlayer animplayer = new AnimationPlayer();


        public AnimationPlayer PlayerAnimationPlayer
        {
            get
            {
                return animplayer;
            }
        }

        // current state decides what the player is doing at any given time
        // probably the most important part of the player
        protected State state;

        public State InternalState
        {
            set
            {
                state = value;
            }
            get
            {
                return state;
            }

        }

        protected Animation anim;
        // current playing animation, set by state
        public Animation PlayerAnimation
        {
            get
            {
                return anim;
            }
            set
            {
                anim = value;
            }

        }



        //animations attached to statenames
        public Dictionary<string, Animation> ATextures = new Dictionary<string, Animation>();

        // for flipping the player 
        // passed to item to determine player direction
        SpriteEffects spriteEffect;

        public SpriteEffects PlayerEffect
        {
            get
            {
                return spriteEffect;
            }
            set
            {
                spriteEffect = value;
            }
        }

        public GameTimer DblJumpTimer;

        public GameTimer DashTimerRight;

        public GameTimer DashTimerLeft;

        //public List<BoxingItem> Items = new List<BoxingItem>();

        public Item[] equippedItems = new Item[4];

        // a state for each item that the player has in their inventory
        public StateUseItem ItemState1;

        public StateUseItem ItemState2;

        public StateUseItem ItemState3;

        public StateUseItem ItemState4;


        public delegate void UseItemEventHandler(ItemInstance item);

        public event UseItemEventHandler OnUseItem;

        #endregion

        public DirectionType direction;

        public BoxingPlayer(float x, float y, string name, int playerindex, int width, int height, Input_Handler input)
        {
            this.width = width;
            this.height = height;
            this.input = input;
            this.isActive = input.isActive;

            this.playerindex = playerindex;
            this.sname = name;

            // initial state
            this.state = new StateMoving();
            direction = DirectionType.Right;


            CurrentHealth = Tools.BASE_HEALTH;
            maxcooldown = Tools.BASE_COOLDOWN;
            maxmovement = Tools.BASE_MOVEMENT;
            CurrentStamina = Tools.BASE_STAMINA;

            position = new Vector3(x, y, Tools.JUMP_HEIGHT);

            DblJumpTimer = new GameTimer(WaitTimerInterval, TimerInterval);

            DashTimerRight = new GameTimer(WaitTimerInterval, TimerInterval);

            DashTimerLeft = new GameTimer(WaitTimerInterval, TimerInterval);

            hurtbox = new Rectangle((int)position.X - width/2, (int)position.Y - height, width, height);
            Debug.WriteLine("Hurtbox.Width = " + Hurtbox.Width + "\nHurtbox.Height = " +
                    Hurtbox.Height);


            spriteEffect = SpriteEffects.None;


        }

        public void LoadContent(ContentManager Content, Dictionary<string, Animation> ATextures, Item[] Items)
        {

            this.ATextures = ATextures;

            hit_textures.Add(Content.Load<Texture2D>("Boxing/money_coin"));
            hit_textures.Add(Content.Load<Texture2D>("Boxing/money_bill"));

            tShadow = Content.Load<Texture2D>("Boxing/player_shadow");
            rShadow = new Rectangle(hurtbox.X, hurtbox.Bottom, hurtbox.Width, hurtbox.Height / 4);

            //ugly code is bad and i feel bad
            //this.Width = 30;
            //this.Height = 30;

            //===============================

            //foreach (Item item in Items)
           // {
                //if (item is Cane)
                //    this.Items.Add((new BoxingCane(Position.X, Position.Y, Width, Height, this, input)));
                //TODO: Add more if statements for more items. Maybe try switch

           // }
            for (int i = 0; i < 4; i++)
            {
                if (Items[i] != null)
                {
                    equippedItems[i] = Items[i];
                    currenthealth += Items[i].health;
                    currentstamina += Items[i].stamina;
                }
                else
                {
                    Debug.WriteLine("Item " + i + " is null!");
                }
            }

            maxhealth = currenthealth;
            maxstamina = currentstamina;

            //for (int i = 0; i < Items.Count; i++)
            //{
               // this.Items[i].LoadContent(Content, Items[i]);
            //}

            state.LoadState(this, ATextures);



            //ItemState1 = new StateUseItem(this.InternalState, this.Items[0]);
            //ItemState2 = new StateUseItem(this.InternalState, this.Items[1]);
            //ItemState3 = new StateUseItem(this.InternalState, this.Items[2]);
            //ItemState4 = new StateUseItem(this.InternalState, this.Items[3]);

            animplayer.PlayAnimation(state.PlayerAnimation);

            input.OnKeyDown += HandleKeyDown;
            input.OnKeyRelease += HandleKeyRelease;

        }

        public void update(GameTime gameTime)
        {
            animplayer.PlayAnimation(state.PlayerAnimation);

            InternalState.Update(gameTime);

            hurtbox.X = (int)position.X - width / 2;
            hurtbox.Y = (int)position.Y - height;
            rShadow.X = hurtbox.X;
            rShadow.Y = hurtbox.Bottom - 5 - rShadow.Height;

            /*foreach (BoxingItem item in Items)
            {
                item.Update();
            }*/

            if (particleEngines_hit.Count >= 0)
            {
                for(int i = particleEngines_hit.Count - 1; i >= 0; i--)
                {
                    particleEngines_hit[i].Update();
                    if (particleEngines_hit[i].isComplete)
                    {
                        particleEngines_hit.RemoveAt(i);
                    }

                }
            }

            HandleState();

            handleMovement();

            handleDirection();


        }



        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            if (input.isActive)
            {
                spriteBatch.Draw(tShadow, rShadow, Color.White * .7f);
                animplayer.Draw(gameTime, spriteBatch, Color.White, Tools.toVector2(position), 0, Vector2.Zero, 3f, spriteEffect);
                if (particleEngines_hit.Count >= 0)
                {
                    foreach (ParticleEngine e in particleEngines_hit)
                        e.Draw(spriteBatch);
                }

                //foreach (BoxingItem item in Items)
                //{
                //    item.Draw(gameTime, spriteBatch);
                //}
            }
        }

        public void HandleKeyDown(int player_index, KeyPressed key)
        {
            if (!KeysDown.Contains(key))
                KeysDown.Add(key);
        }

        public void HandleKeyRelease(int player_index, KeyPressed key)
        {
            if (KeysDown.Contains(key))
                KeysDown.Remove(key);

            if (key == KeyPressed.Up)
                DblJumpTimer.Start();

            if (key == KeyPressed.Right)
                DashTimerRight.Start();

            if (key == KeyPressed.Left)
                DashTimerLeft.Start();
        }



        public void HandleState()
        {
            state.HandleState();
        }

        public void handleDirection()
        {
            state.HandleDirection();
            /*foreach (BoxingItem item in Items)
            {
                item.HandleDirection(PlayerEffect);
            }*/
        }

        public void handleMovement()
        {
            state.HandleMovement();
        }

        public void handleCollision(List<BoxingPlayer> Players)
        {
            state.HandleCollision(Players);
        }

        public void Hit(Item item, DirectionType direction, int vertical_hit)
        {
            
            State state = InternalState;
            InternalState = new StateHit(state, item, direction, vertical_hit, item.attack/5);
            currenthealth -= item.attack;
        }

        public bool isKeyDown(KeyPressed key)
        {
            return this.KeysDown.Contains(key);
        }

        public void UseItemEvent(int itemindex)
        {
            if (equippedItems[itemindex] != null && OnUseItem != null)
            {

                State state = InternalState;
                InternalState = equippedItems[itemindex].GenerateState(itemindex, direction, state);

            }
        }

        public void CreateInstance(int itemindex)
        {
            if (equippedItems[itemindex] != null && OnUseItem != null)
            {
                SpriteEffects effect = SpriteEffects.None;

                if (direction == DirectionType.Right)
                {
                    effect = SpriteEffects.FlipHorizontally;
                }

                OnUseItem(equippedItems[itemindex].GenerateInstance(
                        new Vector3(position.X, position.Y, position.Z), playerindex, effect));
            }
        }
        
        public int CompareTo(BoxingPlayer player)
        {
            return this.Position.Y.CompareTo(player.Position.Y);
        }

    }
}
